﻿#include "Client.h"

#include <QTime>
#include <QString>
#include "qdatastream.h"
#include "qglobal.h"
#include <QUuid>
#include <QBuffer>
#include <QMessageBox>
#include <QHostInfo>
#include <QSettings>
#include <QCoreApplication>
#include <QDir>


Client::Client(QObject *parent)
    :QObject(parent)
{
//    mName = QUuid::createUuid().toString();

    QString randCode = QUuid::createUuid().toString().toUpper();
    randCode = randCode.mid(1,8);

    mName = QHostInfo::localHostName() + "_" + randCode;  //名称后增加一个随机码
    mRoom = FIR_DEFAULT_ROOM;
    mBlack = true;
    mHeartBeatTime = QDateTime::currentDateTime();

    mSocket = new QTcpSocket(this);
    connect(mSocket, &QTcpSocket::connected,this,&Client::slotConnect);
    connect(mSocket, &QTcpSocket::disconnected,this,&Client::slotDisconnect);
    connect(mSocket, &QTcpSocket::readyRead, this, &Client::slotTcpMsg);
}

void Client::GetRoomState(QList<ROOM_STATE> &state)
{
    state = mRoomState;
}

void Client::ConnectToServer(QString ip, int port, int room)
{
    mRoom = room;
    mSocket->connectToHost(ip, port);
}

void Client::slotConnect()
{
    //建立TCP连接成功，第一个消息发送登陆内容，服务器进行确认是否能登陆到指定房间
    SendMsg_Logon();

    //连接成功后开始定时发心跳给服务器，保活
    mTimerHeart = startTimer(3000);
}

void Client::slotDisconnect()
{
    Output(QStringLiteral("与服务器的连接中断！"));

}

void Client::slotTcpMsg()
{
    int nHeaderLen = sizeof(MSG_HEADER);
    if (mSocket->bytesAvailable() <= 0)
    {
        return;
    }
    QByteArray data = mSocket->readAll();
    mData += data;

    while(1)
    {
        if (mData.size() < nHeaderLen)
        {
            //当前接收内容不足一个消息头长度，无法处理继续接收
            return;
        }
        MSG_HEADER* pMsg = (MSG_HEADER*)mData.data();
        if (mData.size() < nHeaderLen + pMsg->nDataLen)
        {
            //当前接收内容足一个消息头，但不足解析本消息需要的总长度(头长度+头里指定的数据长度)
            return;
        }

        //判断是不是客户端认识的消息
        if (pMsg->nType == MA_LOGON ||
            pMsg->nType == MA_MOVE ||
            pMsg->nType == MA_START ||
            pMsg->nType == MA_SAY ||
            pMsg->nType == MA_HEARTBEAT ||
            pMsg->nType == MA_UPDATEROOMSTATE ||
            pMsg->nType == MA_OFFLINE )
        {

        }
        else
        {
            //不认识的消息
            mData.clear();
            return;
        }

        OnMsg(pMsg, (char*)(pMsg + 1), pMsg->nDataLen);

        mData.remove(0, nHeaderLen + pMsg->nDataLen);
    }
}

void Client::OnMsg(MSG_HEADER* pHeader, char *pData, int nDataLen)
{
    switch ( pHeader->nType )
    {
    case MA_LOGON:
    {
        OnMsg_Logon(pHeader);
        break;
    }
    case MA_START:
    {
        OnMsg_Start(pHeader);
        break;
    }
    case MA_MOVE:
    {
        OnMsg_Move(pHeader);
        break;
    }
    case MA_SAY:
    {
        OnMsg_Say(pHeader);
        break;
    }
    case MA_HEARTBEAT:
    {
        //OnMsg_Heartbeat(pHeader);
        break;
    }
    case MA_UPDATEROOMSTATE:
    {
        OnMsg_UpdateRoomState(pHeader, pData, nDataLen);
        break;
    }
    case MA_OFFLINE:
    {
        OnMsg_Offline(pHeader);
        break;
    }
    default:
    {
        break;
    }
    }
}

bool Client::SendMsg_Logon()
{
    MSG_HEADER msg = {0};
    msg.nType = MQ_LOGON;
    msg.nNum1 = mRoom;
    strcpy(msg.szName, mName.toLocal8Bit());

    Send(msg);
    return true;
}

bool Client::SendMsg_Move(int x,int y)
{
    MSG_HEADER msg = {0};
    msg.nType = MQ_MOVE;
    msg.nNum1 = x;
    msg.nNum2 = y;
    strcpy(msg.szName, mName.toLocal8Bit());

    Send(msg);

    return true;
}

bool Client::SendMsg_Success()
{
    MSG_HEADER msg = {0};
    msg.nType = MQ_SUCCESS;
    strcpy(msg.szName, mName.toLocal8Bit());

    Send(msg);

    return true;
}

bool Client::SendMsg_Say(QString text)
{
    MSG_HEADER msg = {0};
    msg.nType = MQ_SAY;
    strcpy(msg.szName, mName.toLocal8Bit());
    strcpy(msg.szSay, text.toLocal8Bit());

    Send(msg);

    return true;
}

void Client::SendMsg_HeartBeat()
{
    MSG_HEADER msg = {0};
    msg.nType = MQ_HEARTBEAT;
    strcpy(msg.szName, mName.toLocal8Bit());

    Send(msg);
}

void Client::OnMsg_Logon(MSG_HEADER* msg)
{
    if(msg->nNum1 == 1)
    {
        QString name = QString::fromLocal8Bit(msg->szName);
        Output(QStringLiteral("%1 进入了本房间！").arg(name));

        if(msg->nNum3 == 1)
        {
            Output(QStringLiteral("当前房间已有1人，请再等待一位玩家进入！").arg(name));
        }
    }
    else
    {
        Output(QStringLiteral("登陆失败！"));
    }
}

void Client::OnMsg_Start(MSG_HEADER *pHeader)
{
    mBlack = (pHeader->nNum2 == 1);

    Output(QStringLiteral("房间已坐满，游戏开始！"));
    if(mBlack)
    {
        Output(QStringLiteral("你执黑棋，请先下！"));
    }
    else
    {
        Output(QStringLiteral("你执白棋，等待对方黑棋先下！"));
    }

    emit sigNewGame();
}

void Client::OnMsg_Move(MSG_HEADER* pHeader)
{
    emit sigOtherUserMove(pHeader->nNum1,pHeader->nNum2);
}

void Client::OnMsg_Say(MSG_HEADER *pHeader)
{
    QString name = QString::fromLocal8Bit(pHeader->szName);
    QString text = QString::fromLocal8Bit(pHeader->szSay);

    QString msg = QStringLiteral("%1说：%2").arg(name).arg(text);
    if(text.contains(QStringLiteral("拍拍")))
    {
        if(name == mName)
        {
            msg = QStringLiteral("你 拍了拍 对方");
        }
        else
        {
            msg = QStringLiteral("%1 拍了拍 你").arg(name);
        }
    }
    Output(msg);
}

void Client::OnMsg_Offline(MSG_HEADER *pHeader)
{
    QString name = QString::fromLocal8Bit(pHeader->szName);
    QString msg = QStringLiteral("玩家%1断开连接……").arg(name);
    Output(msg);
}

void Client::OnMsg_UpdateRoomState(MSG_HEADER *pHeader, char *pData, int nDataLen)
{
    mRoomState.clear();

    //100个房间的玩家数、玩家信息
	ROOM_STATE* p = (ROOM_STATE*)(pData);
    for(int i = 0; i < FIR_MAX_ROOM; i++)
	{
		mRoomState.append(*p); 
		p++;
    }
    emit sigUpdateRoomState();
}

bool Client::IsBlack()
{
    return mBlack;
}

bool Client::Send(MSG_HEADER msg)
{
    mSocket->write((char*)&msg,sizeof(MSG_HEADER));
    mSocket->flush();
    return true;
}

bool Client::Send(MSG_HEADER msg, char *pData, int nDataLen)
{
    int nLen = sizeof(MSG_HEADER) + nDataLen;
    char* buf = new char[nLen];
    memset(buf,0,nLen);

    memcpy(buf,(char*)&msg,sizeof(MSG_HEADER));
    memcpy(buf + sizeof(MSG_HEADER),pData,nDataLen);

    mSocket->write((char*)&msg,sizeof(MSG_HEADER));
    mSocket->flush();

    delete []buf;
    return true;
}

void Client::Output(QString text)
{
    emit sigOutput(text);
}

void Client::timerEvent(QTimerEvent *e)
{
    if(e->timerId() == mTimerHeart)
    {
        SendMsg_HeartBeat();
    }
}







